/*
 *    Copyright (C) 2011-2012 Hai Bison
 *
 *    See the file LICENSE at the root directory of this project for copying
 *    permission.
 */

/*
 * PanelPreferencesEmailProviders.java
 *
 * Created on Sep 10, 2011, 6:40:23 PM
 */
package group.pals.mailgate.preferences.ui;

import group.pals.mailgate.beans.ItemEmailProvider;
import group.pals.mailgate.ui.IPreferences;
import group.pals.mailgate.ui.JSpinnerMouseWheelHandler;
import group.pals.mailgate.ui.RightAlignCellRenderer;
import group.pals.mailgate.ui.Utils;
import group.pals.mailgate.preferences.Preferences;
import group.pals.utils.sys.MessageBox;
import group.pals.utils.ui.JEditorPopupMenu;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import javax.swing.AbstractAction;
import javax.swing.KeyStroke;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.text.JTextComponent;

/**
 *
 * @author Hai Bison
 */
public class PanelPreferencesEmailProviders extends javax.swing.JPanel implements IPreferences {

    private final Utils UIUtils;
    private final DefaultTableModel TableModel;
    private final Map<String, Integer> MapCols;
    private final Preferences _Preferences;

    /** Creates new form PanelPreferencesEmailProviders */
    public PanelPreferencesEmailProviders() {
        initComponents();

        UIUtils = Utils.getInstance();
        _Preferences = Preferences.getInstance();

        initActions();
        initListeners();
        initTable();

        TableModel = (DefaultTableModel) tableEmailProviders.getModel();
        MapCols = new HashMap<String, Integer>();
        for (String header : TableHeaders) {
            MapCols.put(header, tableEmailProviders.getColumn(header).getModelIndex());
        }

        initUI();
    }

    private void initActions() {
        actionAddNewEmailProvider = new ActionAddNewEmailProvider();
        actionRemoveEmailProvider = new ActionRemoveEmailProvider();
        actionClearAllEmailProviders = new ActionClearAllEmailProviders();
        actionSaveEmailProvider = new ActionSaveEmailProvider();

        btnAddNewEmailProvider.setAction(actionAddNewEmailProvider);
        btnRemoveEmailProvider.setAction(actionRemoveEmailProvider);
        btnClearAllEmailProviders.setAction(actionClearAllEmailProviders);
        btnSave.setAction(actionSaveEmailProvider);
    }

    private void initListeners() {
        Component[] components = {txtEmailProviderName, txtEmailPattern, txtImapHost, txtImapPort};

        DocumentListener documentListener = new DocumentListener() {

            public void insertUpdate(DocumentEvent e) {
                doHandle();
            }

            public void removeUpdate(DocumentEvent e) {
                doHandle();
            }

            public void changedUpdate(DocumentEvent e) {
                doHandle();
            }

            private void doHandle() {
                actionSaveEmailProvider.setEnabled(true);
            }
        };

        for (Component comp : components) {
            if (comp instanceof JTextComponent) {
                ((JTextComponent) comp).getDocument().addDocumentListener(documentListener);
            }
        }

        txtImapPort.addChangeListener(new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                actionSaveEmailProvider.setEnabled(true);
            }
        });

        JSpinnerMouseWheelHandler mwh = JSpinnerMouseWheelHandler.getInstance();
        SpinnerNumberModel numberModel = new SpinnerNumberModel(0, 0, 65535, 1000);
        txtImapPort.setModel(numberModel);
        txtImapPort.addMouseWheelListener(mwh);

        KeyAdapter keyAdapter = new KeyAdapter() {

            @Override
            public void keyReleased(KeyEvent e) {
                switch (e.getKeyCode()) {
                    case KeyEvent.VK_ENTER: {
                        if (actionSaveEmailProvider.isEnabled()) {
                            actionSaveEmailProvider.actionPerformed(new ActionEvent(e.getSource(), ActionEvent.ACTION_PERFORMED, ""));
                        }
                    }//VK_ENTER

                    case KeyEvent.VK_ESCAPE: {
                        loadDetailsEmailProvider(getSelectedEmailProvider());
                    }//VK_ESCAPE
                }
            }
        };

        for (Component comp : components) {
            comp.addKeyListener(keyAdapter);
        }
    }
    /*----------------------------------------------------------------------------
     * Table Data
     */
    private final String ColRowNo = "#";
    private final String ColProviderName = "Name";
    private final String ColEmailPattern = "E-mail Pattern";
    private final String ColImapHost = "IMAP Host";
    private final String ColImapPort = "IMAP Port";
    private final String[] TableHeaders = {ColRowNo, ColProviderName, ColEmailPattern,
        ColImapHost, ColImapPort};
    private final Class[] TableHeaderClasses = {String.class, ItemEmailProvider.class,
        String.class, String.class, Integer.class};

    //<editor-fold defaultstate="collapsed" desc="table initialization">
    private void initTable() {
        tableEmailProviders.setModel(new javax.swing.table.DefaultTableModel(
                new Object[][]{}, TableHeaders) {

            @Override
            public Class getColumnClass(int columnIndex) {
                return TableHeaderClasses[columnIndex];
            }

            @Override
            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return false;
            }

            @Override
            public Object getValueAt(int row, int column) {
                final String ColName = getColumnName(column);

                if (ColName.equals(ColRowNo)) {
                    return String.format("%,02d", row + 1);
                } else if (ColName.equals(ColProviderName)) {
                    return super.getValueAt(row, column);
                } else {
                    ItemEmailProvider ep = (ItemEmailProvider) super.getValueAt(row, MapCols.get(ColProviderName));

                    if (ColName.equals(ColEmailPattern)) {
                        return ep.getEmailPattern();
                    } else if (ColName.equals(ColImapHost)) {
                        return ep.getImapHost();
                    } else if (ColName.equals(ColImapPort)) {
                        return ep.getImapPort();
                    }

                    return super.getValueAt(row, column);
                }
            }//getValueAt()
        });

        //------------------------ Init columns
        RightAlignCellRenderer rightAlignCellRenderer = new RightAlignCellRenderer();
        rightAlignCellRenderer.setCellHorzAlignment(SwingConstants.RIGHT);

        TableColumn col = tableEmailProviders.getColumn(ColRowNo);
        col.setCellRenderer(rightAlignCellRenderer);
        col.setMinWidth(50);
        col.setMaxWidth(50);

        col = tableEmailProviders.getColumn(ColImapPort);
        col.setCellRenderer(rightAlignCellRenderer);
        col.setMinWidth(80);
        col.setMaxWidth(80);

        //listeners
        tableEmailProviders.getSelectionModel().addListSelectionListener(new ListSelectionListener() {

            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()) {
                    loadDetailsEmailProvider(getSelectedEmailProvider());
                }
            }
        });

        tableEmailProviders.getModel().addTableModelListener(new TableModelListener() {

            public void tableChanged(TableModelEvent e) {
                loadDetailsEmailProvider(e.getType() == TableModelEvent.DELETE ? null : getSelectedEmailProvider());
            }
        });
    }// </editor-fold>

    private void initUI() {
        JEditorPopupMenu editorPopupMenu = UIUtils.getEditorPopupMenu();
        txtEmailProviderName.setComponentPopupMenu(editorPopupMenu);
        txtEmailPattern.setComponentPopupMenu(editorPopupMenu);
        txtImapHost.setComponentPopupMenu(editorPopupMenu);
        txtImapPort.setComponentPopupMenu(editorPopupMenu);
    }

    private void loadDetailsEmailProvider(ItemEmailProvider emailProvider) {
        txtEmailProviderName.setText(emailProvider == null ? null : emailProvider.getName());
        txtEmailPattern.setText(emailProvider == null ? null : emailProvider.getEmailPattern());
        txtImapHost.setText(emailProvider == null ? null : emailProvider.getImapHost());
        txtImapPort.setValue(emailProvider == null ? 0 : emailProvider.getImapPort());

        group.pals.utils.ui.Utils.enableContainer(panelDetails, emailProvider != null);
        actionSaveEmailProvider.setEnabled(emailProvider != null);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jToolBar1 = new javax.swing.JToolBar();
        btnAddNewEmailProvider = new javax.swing.JButton();
        jSeparator3 = new javax.swing.JToolBar.Separator();
        btnRemoveEmailProvider = new javax.swing.JButton();
        jSeparator4 = new javax.swing.JToolBar.Separator();
        btnClearAllEmailProviders = new javax.swing.JButton();
        jScrollPane2 = new javax.swing.JScrollPane();
        tableEmailProviders = new javax.swing.JTable();
        panelDetails = new javax.swing.JPanel();
        txtEmailProviderName = new javax.swing.JTextField();
        txtEmailPattern = new javax.swing.JTextField();
        txtImapHost = new javax.swing.JTextField();
        txtImapPort = new javax.swing.JSpinner();
        btnSave = new javax.swing.JButton();

        setLayout(new java.awt.GridBagLayout());

        jToolBar1.setFloatable(false);
        jToolBar1.setRollover(true);

        btnAddNewEmailProvider.setText("jButton1");
        btnAddNewEmailProvider.setFocusable(false);
        btnAddNewEmailProvider.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnAddNewEmailProvider.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jToolBar1.add(btnAddNewEmailProvider);
        jToolBar1.add(jSeparator3);

        btnRemoveEmailProvider.setText("jButton2");
        btnRemoveEmailProvider.setFocusable(false);
        btnRemoveEmailProvider.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnRemoveEmailProvider.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jToolBar1.add(btnRemoveEmailProvider);
        jToolBar1.add(jSeparator4);

        btnClearAllEmailProviders.setText("jButton3");
        btnClearAllEmailProviders.setFocusable(false);
        btnClearAllEmailProviders.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnClearAllEmailProviders.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jToolBar1.add(btnClearAllEmailProviders);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        add(jToolBar1, gridBagConstraints);

        jScrollPane2.setBorder(javax.swing.BorderFactory.createTitledBorder("Providers (must support SSL):"));

        tableEmailProviders.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {

            }
        ));
        tableEmailProviders.getTableHeader().setReorderingAllowed(false);
        jScrollPane2.setViewportView(tableEmailProviders);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weighty = 1.0;
        add(jScrollPane2, gridBagConstraints);

        panelDetails.setBorder(javax.swing.BorderFactory.createTitledBorder("Details:"));
        panelDetails.setLayout(new java.awt.GridBagLayout());

        txtEmailProviderName.setBorder(javax.swing.BorderFactory.createTitledBorder("Name:"));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        panelDetails.add(txtEmailProviderName, gridBagConstraints);

        txtEmailPattern.setBorder(javax.swing.BorderFactory.createTitledBorder("E-mail pattern:"));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        panelDetails.add(txtEmailPattern, gridBagConstraints);

        txtImapHost.setBorder(javax.swing.BorderFactory.createTitledBorder("IMAP host:"));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        panelDetails.add(txtImapHost, gridBagConstraints);

        txtImapPort.setBorder(javax.swing.BorderFactory.createTitledBorder("IMAP port:"));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 0.5;
        panelDetails.add(txtImapPort, gridBagConstraints);

        btnSave.setText("jButton1");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTHEAST;
        gridBagConstraints.weightx = 0.5;
        panelDetails.add(btnSave, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        add(panelDetails, gridBagConstraints);
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnAddNewEmailProvider;
    private javax.swing.JButton btnClearAllEmailProviders;
    private javax.swing.JButton btnRemoveEmailProvider;
    private javax.swing.JButton btnSave;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JToolBar.Separator jSeparator3;
    private javax.swing.JToolBar.Separator jSeparator4;
    private javax.swing.JToolBar jToolBar1;
    private javax.swing.JPanel panelDetails;
    private javax.swing.JTable tableEmailProviders;
    private javax.swing.JTextField txtEmailPattern;
    private javax.swing.JTextField txtEmailProviderName;
    private javax.swing.JTextField txtImapHost;
    private javax.swing.JSpinner txtImapPort;
    // End of variables declaration//GEN-END:variables

    /*----------------------------------------------------------------------------
     * IPreferences
     */
    public void loadPreferences() {
        TableModel.setRowCount(0);

        List<ItemEmailProvider> emailProviders = _Preferences.getEmailProviders();
        Object[] row = new Object[TableHeaders.length];
        for (ItemEmailProvider ep : emailProviders) {
            row[MapCols.get(ColProviderName)] = ep;
            TableModel.addRow(row);
        }
        TableModel.fireTableDataChanged();

        group.pals.utils.ui.Utils.enableContainer(panelDetails, false);
    }

    public boolean storePreferences(boolean prepare) {
        if (TableModel.getRowCount() == 0) {
            MessageBox.showErrMsg(this, null, "Please setup at least one provider!");
            return false;
        }

        if (prepare) {
            return true;
        }

        List<ItemEmailProvider> emailProviders = new ArrayList<ItemEmailProvider>();
        for (int r = 0; r < TableModel.getRowCount(); r++) {
            ItemEmailProvider ep = (ItemEmailProvider) TableModel.getValueAt(r, MapCols.get(ColProviderName));
            emailProviders.add(ep);
        }

        _Preferences.setEmailProviders(emailProviders);

        return true;
    }

    public void closeResources() {
        //do nothing
    }

    public ItemEmailProvider getSelectedEmailProvider() {
        if (tableEmailProviders.getSelectedRow() >= 0) {
            return (ItemEmailProvider) tableEmailProviders.getValueAt(
                    tableEmailProviders.getSelectedRow(), MapCols.get(ColProviderName));
        }
        return null;
    }

    /*----------------------------------------------------------------------------
     * ACTIONS
     */

    /*----------------------------------------------------------------------------
     * ActionAddNewEmailProvider
     */
    private ActionAddNewEmailProvider actionAddNewEmailProvider;

    private class ActionAddNewEmailProvider extends AbstractAction {

        public ActionAddNewEmailProvider() {
            super("Add New...");
        }

        public void actionPerformed(ActionEvent e) {
            Object[] row = new Object[TableHeaders.length];
            row[MapCols.get(ColProviderName)] = new ItemEmailProvider("Unknown", "(?sim).*@", "host", 0, true);
            TableModel.addRow(row);
            int r = tableEmailProviders.getRowCount() - 1;
            tableEmailProviders.setRowSelectionInterval(r, r);
            txtEmailProviderName.requestFocusInWindow();
            txtImapPort.setValue(Preferences.DefImapPort);
        }
    }

    /*----------------------------------------------------------------------------
     * ActionRemoveEmailProvider
     */
    private ActionRemoveEmailProvider actionRemoveEmailProvider;

    private class ActionRemoveEmailProvider extends AbstractAction {

        public ActionRemoveEmailProvider() {
            super("Remove");
        }

        public void actionPerformed(ActionEvent e) {
            if (tableEmailProviders.getSelectedRowCount() > 0
                    && MessageBox.confirmYesNo(null, null,
                    "Are you sure you want to remove selected provider(s)?", 1)) {
                for (int r = tableEmailProviders.getRowCount(); r >= 0; r--) {
                    if (tableEmailProviders.isRowSelected(r)) {
                        TableModel.removeRow(tableEmailProviders.convertRowIndexToModel(r));
                    }
                }
                TableModel.fireTableDataChanged();
            }
        }
    }
    /*----------------------------------------------------------------------------
     * ActionClearAllEmailProviders
     */
    private ActionClearAllEmailProviders actionClearAllEmailProviders;

    private class ActionClearAllEmailProviders extends AbstractAction {

        public ActionClearAllEmailProviders() {
            super("Clear All");
        }

        public void actionPerformed(ActionEvent e) {
            if (TableModel.getRowCount() > 0
                    && MessageBox.confirmYesNo(null, null, "Are you sure you want to clear all providers?", 1)) {
                TableModel.setRowCount(0);
            }
        }
    }
    /*----------------------------------------------------------------------------
     * ActionSaveEmailProvider
     */
    private ActionSaveEmailProvider actionSaveEmailProvider;

    private class ActionSaveEmailProvider extends AbstractAction {

        public ActionSaveEmailProvider() {
            super("Save");
            putValue(ACCELERATOR_KEY,
                    KeyStroke.getKeyStroke('S', InputEvent.CTRL_DOWN_MASK));
        }

        public void actionPerformed(ActionEvent e) {
            if (tableEmailProviders.getSelectedRowCount() != 1) {
                return;
            }

            String emailPattern = txtEmailPattern.getText().trim();
            try {
                Pattern.compile(emailPattern);
            } catch (Exception ex) {
                MessageBox.showErrMsg(null, null, "E-mail pattern is invalid");
                return;
            }

            ItemEmailProvider emailProvider = getSelectedEmailProvider();
            emailProvider.setName(txtEmailProviderName.getText().trim());
            emailProvider.setEmailPattern(emailPattern);
            emailProvider.setImapHost(txtImapHost.getText().trim());
            emailProvider.setImapPort((Integer) txtImapPort.getValue());

            setEnabled(false);
            TableModel.fireTableDataChanged();

            //restore last selected row
            final int Col = MapCols.get(ColProviderName);
            for (int row = 0; row < tableEmailProviders.getRowCount(); row++) {
                if (tableEmailProviders.getValueAt(row, Col).equals(emailProvider)) {
                    tableEmailProviders.getSelectionModel().setSelectionInterval(row, row);
                    break;
                }
            }
        }
    }
}
